package com.qiusuo0226.platform.aspect;

import com.qiusuo0226.mysql.service.DatabaseService;
import com.qiusuo0226.platform.annotation.SysUpgrade;
import com.qiusuo0226.platform.constant.Tables;
import com.qiusuo0226.platform.service.SysVersionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author qiusuo
 * @date 2024/3/19 11:08
 */
@Slf4j
@Component
@Aspect
public class SysUpgradeAspect {

    @Autowired
    private SysVersionService sysVersionService;

    @Autowired
    private DatabaseService databaseService;

    public static final String V100 = "1.0.0";

    /**
     * 切入点
     * 匹配使用了SysUpgrade注解的方法
     */
    @Pointcut("@annotation(com.qiusuo0226.platform.annotation.SysUpgrade)")
    private void pt() {}

    /**
     * 环绕通知
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("pt()")
    public Object around(ProceedingJoinPoint point) throws Throwable {

        // 获取方法上的@SysUpgrade注解对象
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = methodSignature.getMethod();
        SysUpgrade annotation = method.getAnnotation(SysUpgrade.class);

        // 获取注解对象属性的值
        // 版本号
        String version = annotation.version();
        // 版本序号
        int order = annotation.order();
        log.info("版本号:{}; 序号:{}", version, order);


        if (StringUtils.equals(version, V100)) {


            // 查项目连接的数据库中有没有那张表
            boolean tableExsit = databaseService.tableExsit(Tables.SYS_VSERSION);
            if (!tableExsit) {
                log.info("项目部署:{} ...... 开始 >>>>>>>>>>", version);
                // 执行切点方法，万一原方法存在异常，也从此处抛出
                Object res = point.proceed();

                // 将版本1.0.0升级记录到数据库
                sysVersionService.addVersion(version, order, annotation.developer(), annotation.description());

                log.info("项目部署:{} ...... 结束 >>>>>>>>>>", version);
                return res;
            }

        } else {
            // 查版本号和排序是否存在
            boolean exist = sysVersionService.versionExist(version, order);

            // 不存在就升级。
            if (!exist) {
                log.info("版本升级:{} ...... 开始 >>>>>>>>>>", version);
                // 执行切点方法，万一原方法存在异常，也从此处抛出
                Object res = point.proceed();

                // 将版本升级记录到数据库
                sysVersionService.addVersion(version, order, annotation.developer(), annotation.description());

                log.info("版本升级:{} ...... 结束 >>>>>>>>>>", version);
                return res;
            }
        }
        return null;
    }

    /**
     * 如果升级项目版本抛出异常，则阻止项目启动。
     * @param e
     */
    @AfterThrowing(value = "pt()", throwing = "e")
    public void afterThrowing(Throwable e) {
        log.error("版本升级失败", e);
        System.exit(1);
    }

}
